var canvas  = document.createElement("canvas");
canvas.width = 224;
canvas.height = 224;
var context = canvas.getContext("2d");
function readImage() {
    if ( this.files && this.files[0] ) {
        var FR= new FileReader();
        FR.onload = function(e) {
            var img = new Image();
            img.addEventListener("load", function() {
                context.drawImage(img, 0, 0, 224, 224);
                runExample();
            });
            img.src = e.target.result;
        };       
        FR.readAsDataURL( this.files[0] );
    }
}

// Create an ONNX inference session with WebGL backend.
const session = new onnx.InferenceSession({ backendHint: 'cpu' });

async function loadModel() {
  // Load an ONNX model. This model is SqueezeNet that takes a 1*3*224*224 image and classifies it.
  const outputData = await session.loadModel("../../demo/anet/model.onnx");
  document.getElementById("btn").removeAttribute("hidden");
  document.getElementById("loading").setAttribute("hidden", true);
}

document.getElementById("fileselect").addEventListener("change", readImage, false);
loadModel();

async function runExample() {

    // load image.
    const imageLoader = new ImageLoader(imageSize, imageSize);
    // const imageData = await imageLoader.getImageData(this.files[0].name);
    const imageData = context.getImageData(0, 0, this.canvas.width, this.canvas.height);
  
    // preprocess the image data to match input dimension requirement, which is 1*3*224*224
    const width = imageSize;
    const height = imageSize;
    const preprocessedData = preprocess(imageData.data, width, height);
  
    const inputTensor = new onnx.Tensor(preprocessedData, 'float32', [1, 3, width, height]);
    // Run model with Tensor inputs and get the result.
    const outputMap = await session.run([inputTensor]);
    const outputData = outputMap.values().next().value.data;
  
    // Render the output result in html.
    printMatches(outputData);
  }
  
  /**
   * Preprocess raw image data to match SqueezeNet requirement.
   */
  function preprocess(data, width, height) {
    const dataFromImage = ndarray(new Float32Array(data), [width, height, 4]);
    const dataProcessed = ndarray(new Float32Array(width * height * 3), [1, 3, height, width]);
  
    
    // Realign imageData from [224*224*4] to the correct dimension [1*3*224*224].
    ndarray.ops.assign(dataProcessed.pick(0, 0, null, null), dataFromImage.pick(null, null, 0));
    ndarray.ops.assign(dataProcessed.pick(0, 1, null, null), dataFromImage.pick(null, null, 1));
    ndarray.ops.assign(dataProcessed.pick(0, 2, null, null), dataFromImage.pick(null, null, 2));
    
    // Normalize 0-255 to (-1)-1
    ndarray.ops.divseq(dataProcessed, 255.0);
    ndarray.ops.subseq(dataProcessed.pick(null, 0, null, null), 0.485);
    ndarray.ops.subseq(dataProcessed.pick(null, 1, null, null), 0.456);
    ndarray.ops.subseq(dataProcessed.pick(null, 2, null, null), 0.406);
    ndarray.ops.divseq(dataProcessed.pick(null, 0, null, null), 0.229);
    ndarray.ops.divseq(dataProcessed.pick(null, 1, null, null), 0.224);
    ndarray.ops.divseq(dataProcessed.pick(null, 2, null, null), 0.225);
  
    return dataProcessed.data;
  }
  
  /**
   * Utility function to post-process SqueezeNet output. Find top k ImageNet classes with highest probability.
   */
  function imagenetClassesTopK(classProbabilities, k) {
    if (!k) { k = 5; }
    const probs = Array.from(classProbabilities);
    const probsIndices = probs.map(
      function (prob, index) {
        return [prob, index];
      }
    );
    const sorted = probsIndices.sort(
      function (a,b) {
        if(a[0] < b[0]) {
          return -1;
        }
        if(a[0] > b[0]) {
          return 1;
        }
        return 0;
      }
    ).reverse();
    const topK = sorted.slice(0, k).map(function (probIndex) {
      const iClass = imagenetClasses[probIndex[1]];
      return {
        id: iClass[0],
        index: parseInt(probIndex[1], 10),
        name: iClass[1].replace(/_/g, ' '),
        probability: probIndex[0]
      };
    });
    return topK;
  }
  
  /**
   * Render SqueezeNet output to Html.
   */
  function printMatches(data) {
    let outputClasses = [];
    const empty = [];
    let mean = 0;
    let CLASS_NAMES = ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10"];
    for (let i = 0; i < 10; i++) {
        mean += (i+1) * data[i];
        empty.push({ name: CLASS_NAMES[i], probability: data[i]});
    }
    outputClasses = empty;
    const predictions = document.getElementById('predictions');
    predictions.innerHTML = '';
    const results = [];
    for (let i = 0; i < 10; i++) {
        let prob = Math.round(100 * outputClasses[i].probability);
        results.push(`${outputClasses[i].name}: <progress id="file" value="${prob}" max="100"></progress> ${prob}%`);
    }
    results.push(`Mean: ${Math.round(mean * 100) / 100}`);
    predictions.innerHTML = results.join('<br>');
  }
